package com.fg.common.util;

import com.fg.common.constant.Constant;
import com.fg.common.exception.FgException;
import io.minio.MinioClient;
import io.minio.policy.PolicyType;
import lombok.SneakyThrows;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Properties;
import java.util.UUID;

/**
 * Minio 工具类
 */
public class MinioUtils {

    private static MinioClient minioClient;
    private static String accessKey;
    private static String secretKey;
    private static String endpoint; //服务器地址
    private static String url;      //访问外链
    private static boolean flag = true;    //是否使用外链

    private MinioUtils() {
    }

    //使用默认配置创建MinioClient
    static {
        try {
            Properties properties = new Properties();
            InputStream in = MinioUtils.class.getClassLoader().getResourceAsStream("application.properties");
            properties.load(in);
            accessKey = properties.getProperty("minio.accessKey");
            secretKey = properties.getProperty("minio.secretKey");
            endpoint = properties.getProperty("minio.endpoint");
            url = properties.getProperty("minio.url");
            minioClient = new MinioClient(endpoint, accessKey, secretKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @param endpoint  服务器ip地址
     * @param accessKey
     * @param secretKey
     * @param flag      是否使用外链
     * @throws Exception
     */
    public static void setMinioClient(String endpoint, String accessKey, String secretKey, boolean flag) throws Exception {
        MinioUtils.endpoint = endpoint;
        MinioUtils.accessKey = accessKey;
        MinioUtils.secretKey = secretKey;
        MinioUtils.flag = flag;
        MinioUtils.minioClient = new MinioClient(endpoint, accessKey, secretKey);
    }

    /**
     * 是否使用外链
     *
     * @param flag
     */
    public static void setFlag(boolean flag) {
        MinioUtils.flag = flag;
    }

    public static MinioClient getMinioClient() {
        return minioClient;
    }

    public static String getAccessKey() {
        return accessKey;
    }

    public static String getSecretKey() {
        return secretKey;
    }

    public static String getEndpoint() {
        return endpoint;
    }

    public static String getUrl() {
        return url;
    }

    public static boolean getFlag() {
        return flag;
    }

    /**
     * 创建bucket
     *
     * @param bucketName 桶名称
     * @param policyType 读写权限
     * @throws Exception
     */
    @SneakyThrows
    private static void createBucket(String bucketName, PolicyType policyType) {
        if (!minioClient.bucketExists(bucketName)) {
            //创建bucket
            minioClient.makeBucket(bucketName);
            if (policyType == null) {
                minioClient.setBucketPolicy(bucketName, "*", PolicyType.READ_ONLY);
            } else {
                minioClient.setBucketPolicy(bucketName, "*", policyType);
            }

        } else {
            if (policyType != null) {
                minioClient.setBucketPolicy(bucketName, "*", policyType);
            }
        }
    }


    /**
     * 上传文件
     *
     * @param file        文件
     * @param bucketName  桶名称
     * @param fileName    文件名称
     * @param contentType 文件的 Mime type
     * @param policyType  指定桶的读写权限
     * @return 文件访问链接
     * @throws Exception
     */
    @SneakyThrows
    public static String uploadFile(InputStream file, String bucketName, String fileName, String contentType, PolicyType policyType) {
        //频道上传文件是否为空
        if (null == file) {
            throw new FgException("上传文件不能为空");
        }
        if (bucketName == null || bucketName.length() == 0) {
            throw new FgException("存储桶名称不能为空");
        }

        //判断存储桶是否存在,不存在则创建
        createBucket(bucketName, policyType);

        //开始上传
        if (policyType == null) {
            minioClient.putObject(bucketName, fileName, file, "application/octet-stream");
        } else {
            minioClient.putObject(bucketName, fileName, file, contentType);
        }

        return getUrl(bucketName, fileName);
    }

    /**
     * 上传文件
     *
     * @param file        文件
     * @param bucketName  桶名称
     * @param fileName    文件名称
     * @param contentType 文件的 Mime type
     * @return 文件访问链接
     * @throws Exception
     */
    @SneakyThrows
    public static String uploadFile(InputStream file, String bucketName, String fileName, String contentType) {
        //频道上传文件是否为空
        return uploadFile(file, bucketName, fileName, contentType, null);
    }


    /**
     * 上传文件
     *
     * @param file       文件
     * @param bucketName 桶名称
     * @param fileName   文件名称
     * @param policyType 指定桶的读写权限
     * @return 文件访问链接
     * @throws Exception
     */
    @SneakyThrows
    public static String uploadFile(InputStream file, String bucketName, String fileName, PolicyType policyType) {
        return uploadFile(file, bucketName, fileName, null, policyType);
    }

    /**
     * 上传文件
     *
     * @param file       文件
     * @param bucketName 桶名称
     * @param fileName   文件名称
     * @return 文件访问链接
     * @throws Exception
     */
    @SneakyThrows
    public static String uploadFile(InputStream file, String bucketName, String fileName) {
        return uploadFile(file, bucketName, fileName, null, null);
    }

    /**
     * 上传文件（传入文件后缀名，自动生成文件名称）
     *
     * @param file       文件
     * @param bucketName 桶名称
     * @param postfix    文件后缀名
     * @return 文件访问链接
     * @throws Exception
     */
    @SneakyThrows
    public static String uploadGenerateFileName(InputStream file, String bucketName, String postfix) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss").withZone(ZoneId.of("GMT+8"));
        String uploadFileName = bucketName + "-" +
                formatter.format(LocalDateTime.now()) + "-" + UUID.randomUUID() + postfix;
        return uploadFile(file, bucketName, uploadFileName, null, null);
    }


    /**
     * 上传文件
     *
     * @param file        文件
     * @param bucketName  存储桶名称
     * @param fileName    文件名称
     * @param contentType 文件的 Mime type
     * @param policyType  指定桶的读写权限
     * @return
     */
    @SneakyThrows
    public static String uploadFile(byte[] file, String bucketName, String fileName, String contentType, PolicyType policyType) {
        //频道上传文件是否为空
        if (null == file || 0 == file.length) {
            throw new FgException("上传文件不能为空");
        }
        if (bucketName == null || bucketName.length() == 0) {
            throw new FgException("存储桶名称不能为空");
        }
        //判断存储桶是否存在,不存在则创建
        createBucket(bucketName, policyType);
        InputStream stream = new ByteArrayInputStream(file);
        //开始上传
        if (policyType == null) {
            minioClient.putObject(bucketName, fileName, stream, "application/octet-stream");
        } else {
            minioClient.putObject(bucketName, fileName, stream, contentType);
        }
        return getUrl(bucketName, fileName);
    }

    /**
     * 上传文件
     *
     * @param file        文件
     * @param bucketName  存储桶名称
     * @param fileName    文件名称
     * @param contentType 文件的 Mime type
     * @return
     */
    @SneakyThrows
    public static String uploadFile(byte[] file, String bucketName, String fileName, String contentType) {
        return uploadFile(file, bucketName, fileName, contentType, null);
    }

    /**
     * 上传文件
     *
     * @param file       文件
     * @param bucketName 存储桶名称
     * @param fileName   文件名称
     * @param policyType 指定桶的读写权限
     * @return
     */
    @SneakyThrows
    public static String uploadFile(byte[] file, String bucketName, String fileName, PolicyType policyType) {
        return uploadFile(file, bucketName, fileName, null, policyType);
    }

    /**
     * 上传文件
     *
     * @param file       文件
     * @param bucketName 存储桶名称
     * @param fileName   文件名称
     * @return
     */
    @SneakyThrows
    public static String uploadFile(byte[] file, String bucketName, String fileName) {
        return uploadFile(file, bucketName, fileName, null, null);
    }

    /**
     * 上传文件（传入文件后缀名，自动生成文件名称）
     *
     * @param file       文件
     * @param bucketName 存储桶名称
     * @param postfix    文件后缀名
     * @return
     */
    @SneakyThrows
    public static String uploadGenerateFileName(byte[] file, String bucketName, String postfix) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss").withZone(ZoneId.of("GMT+8"));
        String uploadFileName = bucketName + "-" +
                formatter.format(LocalDateTime.now()) + "-" + UUID.randomUUID() + postfix;
        return uploadFile(file, bucketName, uploadFileName, null, null);
    }


    //文件的外链
    private static String getUrl(String bucketName, String fileName) {
        if (flag) {
            return url + Constant.MINIO + "/" + bucketName + "/" + fileName;
        } else {
            return endpoint + "/" + bucketName + "/" + fileName;
        }
    }
}
